//操作文件，除了上述C接口（当然，C++也有接口，其他语言也有），我们还可以采用系统接口来进行文件访问，

//OS是硬件的管理者
//几乎所有的语言,如果要对文件进行操作,都必须贯穿OS
//操作系统不相信任何人,想要通过操作系统实现一些功能 
//需要通过系统调用接口
//几乎所有的语言,对于文件的操作的函数,它们的底层一定需要使用OS提供的系统调用

//所有的文件操作,表现上都是进程执行对应的函数
//进程对文件的操作
//需要操作系统先打开文件,将文件的相关属性信息加载到内存
//操作系统中,进程:打开的文件 = 1:n
//系统需要把打开的文件在内存中管理起来
//先描述,再组织
//内核中有数据结构
//struct file
//{
//    //包含了打开文件的相关属性
//    //链接属性
//}

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <iostream>
#include <string.h>

using namespace std;

int main()
{

//open接口介绍
//
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <fcntl.h>
//
//int open(const char *pathname, int flags);
//int open(const char *pathname, int flags, mode_t mode);
//
//pathname: 要打开或创建的目标文件
//
//flags: 打开文件时件时，可以传入多个参数选项，用下面的一个或者多个常量进行“或”运算，构成flags。
//
//这里的或运算怎么理解?
//我们平时传递参数的方法,一个参数就代表一个含义,如果你想表达多个含义
//那么你就需要传递多个参数
//这里的 O_WRONLY 和 O_CREAT 等系统宏,他们在系统的文件中定义为(举例,实际不一定这个数据)
//#define O_CREAT 0x1 = 0000 0001
//#define O_WRONLY 0x2 = 0000 0010 
//#define O_RDONLY 0x4 = 0000 0100 
//仔细看这些数据,他们都是只有一个bit位是1的数据,且不重复
//他们按位与后,都会保留他们有1的那一位 
//所以将与之后的数据当作参数传入,那么一个参数就能代表多个含义了
//
//参数:
//O_RDONLY: 只读打开
//O_WRONLY: 只写打开
//O_RDWR : 读，写打开
//这三个常量，必须指定一个且只能指定一个
//O_CREAT : 若文件不存在，则创建它。需要使用mode选项，来指明新文件的访问权限
//O_APPEND: 追加写
//
//返回值：
// 成功：新打开的文件描述符
// 失败：-1
//
//mode_t理解:就是创建的文件的默认权限,如果使用不带mode_t的接口
//那么就是会系统默认给你一个权限
//
//open 函数具体使用哪个，和具体应用场景相关，如目标文件不存在，需要open创建，则第三个参数表示创建文件
//的默认权限,否则，使用两个参数的open。

    //打开或者是创建文件
    int fd1 = open("./log1.txt", O_RDWR | O_CREAT);
    int fd2 = open("./log2.txt", O_RDWR | O_CREAT, 0664);
    int fd3 = open("./log3.txt", O_RDWR | O_CREAT, 0664);
    int fd4 = open("./log4.txt", O_RDWR | O_CREAT, 0664);
    if (fd1 < 0 || fd2 < 0 || fd3 < 0 || fd4 < 0)
    {
        cerr << "open error" << endl;
        return 1;
    }

    cout << fd1 << endl << fd2 << endl << fd3 << endl << fd4 << endl;

    //往文件里面写东西
    //这里的系统调用不会把以前的所有内容全部覆盖了
    //只会覆盖你所写的部分
    const char* msg = "hello world\n";
    int count  = 5;
    ssize_t size1;
    while(count--)
    {
        //fd2是你期望向哪个文件写入内容
        //msg是你想写入的内容是啥
        //strlen(msg),是你期望写入多少内容
        //返回值代表你时间写入了多少内容
       size1 = write(fd2, msg, strlen(msg));
       //在我们写入文件的过程中,我们需要写入'\0'吗?
       //不需要,'\0'作为字符串的结束,只是C的规定
    }

    cout << "actually written: " << size1 << endl;

      
    //读取文件里面的内容
    char buffer[1024];

    //注意这里如果用同一个文件描述符进行操作的话
    //记得要重新使用open函数
    //这里面也是存在着类似于文件指针的东西
    //需要从新指向文件的开头,不然可能会读取不到数据
    fd2 = open("./log2.txt", O_RDONLY);

    ssize_t size2 = read(fd2, buffer, sizeof(buffer) - 1);
    if (size2 > 0)
    {
        //因为写的时候,没有把'\0'写入文件中
        //那么读取的时候,需要把'\0'给带回去
        buffer[size2] = '\0';
        cout << buffer;
    }

    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);

    return 0;
}
